package com.zim.aliot.service.impl;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import com.google.gson.Gson;
import com.zim.aliot.async.AsyncImage;
import com.zim.aliot.async.NotifyCommand;
import com.zim.aliot.constant.RedisConstant;
import com.zim.aliot.dataobject.CarsDo;
import com.zim.aliot.service.CarsService;
import com.zim.aliot.service.DataFilterService;
import com.zim.aliot.service.MessageService;
import com.zim.aliot.service.ReactiveVehicleService;
import com.zim.aliot.vo.VehicleVO;
import com.zim.analysis.Automatic;
import com.zim.analysis.dto.BaseAnlysisDTO;
import com.zim.analysis.po.AckPO;
import com.zim.analysis.po.GpsPO;
import com.zim.analysis.po.PhotoPO;
import com.zim.analysis.util.FormatUtils;
import lombok.extern.slf4j.Slf4j;


@Service
@Slf4j
public class MessageServiceImpl implements MessageService{
	
	

    @Autowired
    private CarsService carsService;
    
    @Autowired
    private DataFilterService dataFilterService;
    
    @Autowired 
    private ReactiveVehicleService reactiveVehicleService;
    
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    
    @Autowired
    private NotifyCommand notifyCommand;
    
    @Autowired
    private AsyncImage asyncImage;
    
    @Autowired
    private Gson gson;
    
    
    public void messageHandle(byte[] bytes) throws Exception {
        BaseAnlysisDTO anlysis = new Automatic().anlysis(bytes);
        if(anlysis instanceof GpsPO) {
            gpsHandle((GpsPO) anlysis);
        }else if (anlysis instanceof AckPO) {
            ackHandle((AckPO)anlysis);
        }else if (anlysis instanceof PhotoPO) {
            imgHandle((PhotoPO)anlysis);
        }else {
            log.error("[解析失败]",FormatUtils.byteToHexStr(bytes));
        }
    }
    
    protected void gpsHandle(GpsPO gpsPO) throws RuntimeException{  
    		CarsDo carsInfo=carsService.find(gpsPO.getDeviceName());
            
            ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
            boolean hasKey = stringRedisTemplate.hasKey(carsInfo.getVin());
            String oldVehicleVO = "";
            if (hasKey) {
                oldVehicleVO = operations.get(carsInfo.getVin());
            }
            
            /**
             * 数据过滤并触发事件
             */
            VehicleVO vehicleVO = dataFilterService.filterHandle(gpsPO, gson.fromJson(oldVehicleVO, VehicleVO.class));
            vehicleVO.setCar_unique_id(carsInfo.getVin());
            
            /**
             * 数据存储
             */
            
            operations.set(carsInfo.getVin(), gson.toJson(vehicleVO), RedisConstant.EXPIRE,TimeUnit.SECONDS);
            
            reactiveVehicleService.save(vehicleVO); 

    }
    
    protected void ackHandle(AckPO ackPO) {
//        log.info("ackPO:{}",ackPO);
        CarsDo carsInfo = carsService.find(ackPO.getDeviceName());
        boolean status = true;
        StringBuffer reason = new StringBuffer();
         
        switch (ackPO.getStatus()) {
            case 0:
                status = true;
                break;
            case 1:
                status = false;

                if (!ackPO.getGear().equals("N") && !ackPO.getGear().equals("P")) {
                    reason.append("档位不在N或P档.");
                }
                if (ackPO.getSpeed() != 0) {
                    reason.append("车未停.");
                }
                if (ackPO.getRunLight() != 0) {
                    reason.append("有车灯未关");
                }
                break;
            case 2:
                status = false;
                reason.append("指令校验失败");
                break;
            default:
                status = false;
                break;
        }
        
        switch (ackPO.getAckType()) {
            case "UPGRADEDEVICE":
                break;
            case "LOCK":
                // 远程开/关锁
            	notifyCommand.ackNotify(carsInfo.getVin(), "LOCK", ackPO.getRequestSerial(), status, reason.toString());
                //notifyCommand.ackNotify(joyCars.get("car_unique_id").toString(), "LOCK", ackInfo.getRequest_sn(),status,reason.toString());
                break;
            case "IGNITE":
                // 远程启/停
            	notifyCommand.ackNotify(carsInfo.getVin(), "IGNITE", ackPO.getRequestSerial(), status, reason.toString());
                //notifyCommand.ackNotify(joyCars.get("car_unique_id").toString(), "IGNITE", ackInfo.getRequest_sn(),status,reason.toString());
                break;
            case "WHISTLE":
                // 鸣笛
            	notifyCommand.ackNotify(carsInfo.getVin(), "WHISTLE", ackPO.getRequestSerial(), status, reason.toString());
                //notifyCommand.ackNotify(joyCars.get("car_unique_id").toString(), "WHISTLE", ackInfo.getRequest_sn(),status,reason.toString());
                break;
            case "BLUETOOTHRESET":
                // 蓝牙复位
                
                break;
            case "BLUETOOTHPASS":
                // 改蓝牙密码
            	notifyCommand.bluePassNotify(carsInfo.getVin(), "BLUETOOTH", ackPO.getRequestSerial(), status);
                //notifyCommand.bluePassNotify(joyCars.get("car_unique_id").toString(), "BLUETOOTH", ackInfo.getRequest_sn(),status);
                break;
            case "PHOTO":
                // 拍照
                
                break;
            case "RENT":
                // 长租
                
                break;
            default:
                break;
        }
        
        
    }
    
    protected void imgHandle(PhotoPO photoPO) {
//        log.info("photoPO:{}",photoPO);
        if( 0 >= photoPO.getSize() ) {
        	log.error("[图片处理]:数据太小");
        	return;
        }
        
        
        CarsDo carsInfo = carsService.find(photoPO.getDeviceName());
        
        //异步定时任务//超时两分钟自动处理图片数据
        asyncImage.image(carsInfo.getVin(),photoPO.getDeviceName());
        
        
        HashOperations<String, String, String> imageHash = stringRedisTemplate.opsForHash();
        
        Map<String, String> imageData = new HashMap<>();
        imageData.put(String.valueOf(photoPO.getNumber()), photoPO.getBis());
        imageData.put("type", photoPO.getPhotoType());
        imageData.put("time", String.valueOf(System.currentTimeMillis()));
        imageData.put("size", String.valueOf(photoPO.getSize()));
        imageData.put("longitude", String.valueOf(photoPO.getLongitude()));
        imageData.put("latitude", String.valueOf(photoPO.getLatitude()));
        
        String imageHashKey = photoPO.getDeviceName()+"_img";
        
        Map<String, String> redisImage = imageHash.entries(imageHashKey);
        
        //判断是否该拼接图片
       
        if(!redisImage.isEmpty()) {
        	if(Integer.valueOf(redisImage.get("size")) != photoPO.getSize()) {
        		
        		StringBuffer image = new StringBuffer();
        		for (int i = 0; i <= Integer.valueOf(redisImage.get("size")); i++) {
        			
                    image.append(redisImage.get(String.valueOf(i))==null?"":redisImage.get(String.valueOf(i)));
                    
                }
        		//推送图片saveImage
        		notifyCommand.saveImage(carsInfo.getVin(), image.toString(), photoPO);
        		//删除数据
        		stringRedisTemplate.delete(imageHashKey);
        	}else {
        		redisImage.put(String.valueOf(photoPO.getNumber()), photoPO.getBis());
        		if(redisImage.size() >= (photoPO.getSize()+5) ) {
        			//数据完整 保存
                    StringBuffer image = new StringBuffer();
                    
                    for (int i = 0; i <= photoPO.getSize(); i++) {

                        image.append(redisImage.get(String.valueOf(i))==null?"":redisImage.get(String.valueOf(i)));
                        
                    }
                    //推送图片并退出saveImage
                    notifyCommand.saveImage(carsInfo.getVin(), image.toString(), photoPO);
                    //删除数据
                    stringRedisTemplate.delete(imageHashKey);
                    return;
        		}
        		
        	}
        	
        }
        
		imageHash.putAll(imageHashKey, imageData);
		stringRedisTemplate.boundValueOps(imageHashKey).expire(RedisConstant.EXPIRE, TimeUnit.SECONDS);
    }
}
